module nade.stack;


struct Stack(T)
{
    size_t  _top;
    T[]     _array;

    void push()
    {
        if(_top >= _array.length)
            _array.length = _array.length*2 + 1;
        ++_top;
    }
    void push(T v)
    {
        if(_top >= _array.length)
            _array.length = _array.length*2 + 1;
        _array[_top] = v;
        ++_top;
    }
    alias push opCatAssign;

    void opCatAssign(T[] vs)
    {
        size_t end = _top + vs.length;
        if(end > _array.length)
            _array.length = end*2;
        _array[_top .. end] = vs;
        _top = end;
    }

    void pop(size_t num)
    {
		assert(_top >= num);
		_top -= num;
    }

    T pop()
    {
        assert(_top > 0);
        return _array[--_top];
    }

    T peek()
    {
        assert(_top > 0);
        return _array[_top - 1];
    }

    bool empty()
    {
        return _top == 0;
    }

    void clear()
    {
        _top = 0;
    }

    size_t length()
    {
        return _top;
    }
	size_t length(size_t rhs)
	{
		_top = rhs;
        if(_top >= _array.length)
            _array.length = _array.length*2 + 1;
		return _top;
	}

    T[] array()
    {
        return _array[0 .. _top];
    }

    T opIndex(size_t i)
    {
		assert(_top > i);
        return _array[_top - i - 1];
    }
    T opIndexAssign(T rhs, size_t i)
    {
		assert(_top > i);
        return _array[_top - i - 1] = rhs;
    }

    Stack dup()
    {
        Stack s;
        s._top = _top;
        s._array = _array.dup;
        return s;
    }

	bool contains(T element)
	{
		foreach(item; array)
			if(item == element)
				return true;

		return false;
	}

	int opApply(int delegate(ref T) dg)
	{
		foreach_reverse(item; array)
		{
			invariant result = dg(item);
			if(result)
				return result;
		}

		return 0;
	}
	int opApplyReverse(int delegate(ref T) dg)
	{
		foreach(item; array)
		{
			invariant result = dg(item);
			if(result)
				return result;
		}

		return 0;
	}
}
